/**
 * 下载 Worker - 处理分块下载任务
 * 
 * 该 Worker 负责在后台线程处理文件分块下载任务，支持：
 * - 单个分块下载
 * - 批量分块并行下载
 * - 下载暂停/恢复/取消功能
 * - 下载进度实时更新
 * - 错误处理和自动重试机制
 * 
 * @module DownloadWorker
 * @author t1h0
 * @version 1.0.0
 */

// 导入HTTP请求工具和请求选项类型
import { request, RequestOptions } from '../../http/request';
// 导入任务类型和批量任务接口
import { CommandResponse, BatchTask } from '../../thread/thread-pool';

/**
 * 下载任务选项接口
 * @interface DownloadTaskOptionsTyoe
 * @property {string} url - 下载URL
 * @property {Object} [headers] - 请求头
 * @property {string} [headers.authToken] - 认证令牌
 * @property {Object} chunk - 分块信息
 * @property {number} chunk.start - 分块起始字节
 * @property {number} chunk.end - 分块结束字节
 * @property {number} chunk.index - 分块索引
 * @property {number} totalBytes - 总字节数
 * @property {number} downloadedBytes - 已下载字节数
 */
export type DownloadTaskOptionsTyoe = {
  /** 下载URL */
  url: string;
  /** 请求头 */
  headers?: {
    /** 认证令牌 */
    authToken?: string;
  };
  /** 分块信息 */
  chunk: {
    /** 分块起始字节 */
    start: number;
    /** 分块结束字节 */
    end: number;
    /** 分块索引 */
    index: number;
  };
  /** 总字节数 */
  totalBytes: number;
  /** 已下载字节数 */
  downloadedBytes: number;
}

/**
 * 下载Worker类 - 处理后台线程中的下载任务
 * @class DownloadWorker
 */
class DownloadWorker {
  /**
   * 最大重试次数
   * @static
   * @readonly
   * @type {number}
   */
  private static readonly MAX_RETRIES = 3;

  // ============== 实例属性 ==============

  /**
   * 批量任务的中止控制器数组
   * @private
   * @type {AbortController[]}
   */
  private batchAbortControllers: AbortController[] = [];
  private batchTaskInfo: {
    /**
     * 批量任务信息
     * @private
     * @type {{ batchId: number; totalTasks: number; completedTasks: number; tasks: Array<{ id: number; data: DownloadTaskOptionsTyoe }>; totalSize: number; } | null}
     */
    batchId: number;
    totalTasks: number;
    completedTasks: number;
    tasks: Array<{ id: number; data: DownloadTaskOptionsTyoe }>;
    totalSize: number;
  } | null = null;

  /**
   * 是否暂停
   * @private
   * @type {boolean}
   */
  private isPaused = false;

  /**
   * 暂停解析器
   * @private
   * @type {(() => void) | null}
   */
  private pauseResolver: (() => void) | null = null;
  private abortController: AbortController | null = null;
  private isProcessing = false;

  /**
   * 处理主线程消息
   * @public
   * @param {MessageEvent} e - 消息事件对象
   * @returns {void}
   */
  public handleMessage(e: MessageEvent): void {
    const { type } = e.data;

    switch (type) {
      case CommandResponse.Command_Task:
        const { taskId, data } = e.data;
        this.__handleSingleTask(taskId, data);
        break;
      case CommandResponse.Command_BatchTask:
        const { batchId, tasks } = e.data as BatchTask<DownloadTaskOptionsTyoe>;
        this.__handleBatchTask(batchId, tasks);
        break;
      case CommandResponse.Command_Pause:
        this.__handlePause();
        break;
      case CommandResponse.Command_Resume:
        this.__handleResume();
        break;
      case CommandResponse.Command_Cancel:
        this.__handleCancel();
        break;
    }
  }

  // ============== 私有方法 ==============

  /**
   * 处理单任务命令
   * @private
   * @param {number} taskId - 任务ID
   * @param {DownloadTaskOptionsTyoe} data - 任务数据
   * @returns {Promise<void>} - 处理完成的Promise
   */
  private async __handleSingleTask(taskId: number, data: DownloadTaskOptionsTyoe): Promise<void> {
    if (!this.isProcessing) {
      this.isProcessing = true;
      try {
        // 持续检查暂停状态
        this.__checkPause();

        // 准备请求选项
        const abortController = new AbortController();
        this.abortController = abortController;

        const options: RequestOptions = {
          url: data.url,
          method: 'GET',
          timeout: Number.MAX_SAFE_INTEGER,
          returnResponse: true,
          signal: abortController.signal
        };
        options.headers = data.headers || {};
        options.headers['Range'] = `bytes=${data.chunk.start}-${data.chunk.end}`;

        if (data.headers?.authToken) {
          options.headers['Authorization'] = data.headers.authToken;
        }

        // 下载当前块
        const response: Response = await request(options);

        if (!response.body) {
          throw new Error(`任务${taskId}响应体为空`);
        }

        // 获取Reader
        const reader = response.body.getReader();

        // 实时处理下载流
        let receivedLength = 0;
        const chunks: BlobPart[] = [];

        while (true) {
          const { done, value } = await reader.read();

          if (done) {
            break;
          }

          chunks.push(value);
          receivedLength += value.length;

          // 更新进度
          self.postMessage({
            type: CommandResponse.Response_Progress,
            taskType: 'task',
            taskId,
            data: {
              totalSize: data.chunk.end - data.chunk.start + 1,
              downloaded: receivedLength
            }
          });

          // 检查是否已中止
          if (abortController.signal.aborted) {
            self.postMessage({
              type: CommandResponse.Response_TaskCanceled,
              taskId
            });
            return;
          }
        }

        // 合并块数据
        const blob = new Blob(chunks);

        self.postMessage({
          type: CommandResponse.Response_TaskComplete,
          taskId,
          data: {
            chunkIndex: data.chunk.index,
            blob
          }
        });
      } catch (error) {
        self.postMessage({
          type: CommandResponse.Response_TaskError,
          taskId,
          error: error instanceof Error ? error.message : String(error)
        });
      } finally {
        this.isProcessing = false;
        this.abortController = null;
      }
    } else {
      self.postMessage({
        type: CommandResponse.Response_Error,
        taskId,
        data: { message: 'Worker is busy' }
      });
    }
  }

  /**
   * 处理批量任务命令
   * @private
   * @param {number} batchId - 批量任务ID
   * @param {Array<{ id: number; data: DownloadTaskOptionsTyoe }>} tasks - 任务数组
   * @returns {Promise<void>} - 处理完成的Promise
   */
  private async __handleBatchTask(batchId: number, tasks: Array<{ id: number; data: DownloadTaskOptionsTyoe }>): Promise<void> {
    // 接收批量任务
    if (!this.isProcessing) {
      // 初始化批量任务信息
      this.batchTaskInfo = {
        batchId,
        totalTasks: tasks.length,
        completedTasks: 0,
        tasks: [...tasks], // 保存任务列表的副本
        totalSize: tasks.reduce((sum, task) => {
          const { chunk: { start, end } } = task.data;
          task.data.totalBytes = end - start + 1;
          task.data.downloadedBytes = 0;
          return sum + task.data.totalBytes;
        }, 0),
      };
      this.isProcessing = true;
      // 处理批量任务并捕获可能的错误
      // 使用Promise链式调用处理成功和失败情况
      this.__processBatchTask(batchId, tasks)
        .then(() => {
          // 正常完成时重置状态
          this.isProcessing = false;
          this.batchTaskInfo = null;
        })
        .catch(error => {
          self.postMessage({
            type: CommandResponse.Response_Error,
            batchId,
            data: { message: error?.message || 'Batch processing failed' }
          });
          this.isProcessing = false;
          console.error('Batch task error:', error);
        });
    } else {
      // console.log('拒绝批量任务ID:', batchId, ',当前处理ID:', this.currentTask?.taskId)
      // 如果已经在处理任务，拒绝新任务
      self.postMessage({
        type: CommandResponse.Response_Error,
        batchId,
        data: { message: 'Worker is busy' }
      });
    }
  }

  /**
   * 处理暂停命令
   * @private
   * @returns {void}
   * @description 暂停当前所有下载任务并保存状态
   */
  private __handlePause(): void {
    // 设置暂停标志
    this.isPaused = true;
    // 重置处理状态，确保恢复时能接受任务
    this.isProcessing = false;
    // 中断当前请求（如果有）
    // 确保在暂停时停止所有网络请求
    if (this.abortController) {
      this.abortController.abort();
      this.abortController = null;
    }
    // 中断所有批量任务请求（如果有）
    // 遍历所有中止控制器并调用abort方法
    if (this.batchAbortControllers && this.batchAbortControllers.length > 0) {
      this.batchAbortControllers.forEach(controller => controller.abort());
      this.batchAbortControllers.length = 0;
    }
    // 通知主线程暂停成功
    // 发送暂停状态和相关批量任务ID
    self.postMessage({
      type: CommandResponse.Response_TaskPaused,
      batchId: this.batchTaskInfo?.batchId || null,
      data: { message: 'Download paused' }
    });
  }

  /**
   * 处理恢复命令
   * @private
   * @returns {void}
   * @description 恢复被暂停的下载任务
   */
  private __handleResume(): void {
    // 清除暂停标志
    // 允许任务继续执行
    this.isPaused = false;
    // 如果有暂停解析器，调用它以继续执行
    // 解析器用于在暂停状态解除时唤醒等待的任务
    if (this.pauseResolver) {
      this.pauseResolver();
      this.pauseResolver = null;
    }
    // 重置处理状态，等待主线程重新发送任务
    this.isProcessing = false;
  }

  /**
   * 处理取消命令
   * @private
   * @returns {void}
   * @description 取消所有正在进行的下载任务
   */
  private __handleCancel(): void {
    // 取消当前请求
    // 确保在取消操作时停止所有网络请求
    if (this.abortController) {
      this.abortController.abort();
      this.abortController = null;
    }
    // 清除暂停状态
    // 确保在取消后任务可以重新开始
    this.isPaused = false;
    if (this.pauseResolver) {
      this.pauseResolver();
      this.pauseResolver = null;
    }
    // 取消所有批量任务请求
    // 确保所有相关请求都被正确中止
    if (this.batchAbortControllers && this.batchAbortControllers.length > 0) {
      this.batchAbortControllers.forEach(controller => controller.abort());
      this.batchAbortControllers.length = 0;
    }
    // 通知主线程批量任务已取消
    // 发送取消通知和相关错误信息
    if (this.batchTaskInfo) {
      self.postMessage({
        type: CommandResponse.Response_Error,
        batchId: this.batchTaskInfo.batchId,
        data: { message: 'Batch task cancelled' }
      });
      this.isProcessing = false;
      this.batchTaskInfo = null;
    }
  }

  /**
   * 检查是否暂停
   * @private
   * @returns {Promise<void>}
   * @description 如果任务被暂停，则等待恢复信号
   */
  private async __checkPause(): Promise<void> {
    while (this.isPaused) {
      await new Promise<void>(resolve => {
        this.pauseResolver = resolve;
      });
      this.pauseResolver = null;
    }
  }

  /**
   * 处理批量下载任务
   * @private
   * @param {number} batchId - 批量任务ID
   * @param {Array<{ id: number; data: DownloadTaskOptionsTyoe }>} tasks - 任务数组
   * @returns {Promise<void>}
   * @description 并行处理多个分块下载任务，处理进度更新和错误重试
   */
  private async __processBatchTask(batchId: number, tasks: Array<{ id: number; data: DownloadTaskOptionsTyoe }>): Promise<void> {
    let totalDownloadedBytes = 0;
    // 清空之前的中止控制器
    this.batchAbortControllers = [];

    // 持续检查暂停状态
    this.__checkPause();

    // 确保批量任务信息已更新
    if (this.batchTaskInfo) {
      this.batchTaskInfo.tasks = [...tasks];
    }

    // 使用Promise.all并行处理所有批量任务
    // 每个任务都会创建一个Promise来处理下载、重试和错误处理
    const taskPromises = tasks.map(task => {
      const { id: taskId, data: { url, headers, chunk: { start, end, index: chunkIndex } } } = task;
      let retryCount = 0;

      return new Promise<{
        taskId: number; success: boolean; data?: { chunkIndex: number; blob: Blob; }; error?: string
      }>(async (resolve) => {
        while (retryCount < DownloadWorker.MAX_RETRIES) {
          // 创建新的中止控制器
          let abortController = new AbortController();
          this.batchAbortControllers.push(abortController);

          try {
            // 持续检查暂停状态
            this.__checkPause();

            // 确保批量任务信息已更新
            if (this.batchTaskInfo) {
              this.batchTaskInfo.tasks = [...tasks];
            }

            // 准备请求选项
            // 设置URL、方法、超时和中止信号
            const options: RequestOptions = {
              url: url,
              method: 'GET',
              timeout: Number.MAX_SAFE_INTEGER,
              returnResponse: true,
              signal: abortController.signal
            };
            options.headers = headers || {};
            options.headers['Range'] = `bytes=${start}-${end}`;

            if (headers?.authToken) {
              options.headers['Authorization'] = headers.authToken;
            }

            // 下载当前块
            // 使用配置好的选项发起请求
            const response: Response = await request(options);

            // 确保响应有body
            // 如果响应体为空，则抛出错误
            if (!response.body) {
              throw new Error(`任务${taskId}响应体为空`);
            }

            // 获取Reader
            // 使用ReadableStreamReader处理响应流
            const reader = response.body.getReader();

            // 实时处理下载流
            // 循环读取数据块直到完成
            let receivedLength = 0;
            const chunks: BlobPart[] = [];

            while (true) {
              const { done, value } = await reader.read();

              if (done) {
                break;
              }

              chunks.push(value);
              receivedLength += value.length;

              // 更新总下载字节数
              // 累积已下载的字节数用于进度计算
              totalDownloadedBytes += value.length;
              console.log(`任务${taskId}已下载${receivedLength}字节`);
              self.postMessage({
                type: CommandResponse.Response_Progress,
                taskType: 'task',
                taskId,
                data: {
                  totalSize: end - start + 1,
                  downloaded: receivedLength
                }
              })

              // 检查是否已中止
              // 如果请求已被中止，则解析为失败并返回
              if (abortController.signal.aborted) {
                resolve({
                  taskId,
                  success: false,
                  error: 'Task cancelled'
                });
                return;
              }
            }

            // 合并块数据
            // 将所有接收到的数据块合并为一个Blob
            const blob = new Blob(chunks);

            resolve({
              taskId,
              success: true,
              data: {
                chunkIndex,
                blob: blob
              }
            });
            break;

          } catch (error: unknown) {
            if (abortController.signal.aborted) {
              resolve({
                taskId,
                success: false,
                error: 'Task cancelled'
              });
              break;
            } else if (retryCount < DownloadWorker.MAX_RETRIES - 1) {
              retryCount++;
              self.postMessage({
                type: CommandResponse.Response_TaskRetry,
                taskId,
                retryCount
              });
              // 指数退避
              // 随着重试次数增加，等待时间呈指数增长
              await new Promise(resolve => setTimeout(resolve, 1000 * retryCount));
            } else {
              const errorMessage = error instanceof Error ? error.message : String(error);
              resolve({
                taskId,
                success: false,
                error: errorMessage
              });
            }
          }
        }
      });
    });

    // 等待所有任务完成（允许部分失败）
    // 使用Promise.allSettled确保即使部分任务失败，也能获取所有结果
    const results = await Promise.allSettled(taskPromises);
    console.log(`批量任务${batchId}已完成，总下载字节数: ${totalDownloadedBytes}`);
    self.postMessage({
      type: CommandResponse.Response_Progress,
      taskType: 'batch',
      batchId,
      data: {
        totalSize: this.batchTaskInfo?.totalSize,
        downloaded: totalDownloadedBytes
      }
    });

    // 处理结果，转换为统一格式
    // 将Promise结果转换为标准格式，无论成功或失败
    const processedResults = results.map((result, index) => {
      const originalTask = tasks[index];
      if (result.status === 'fulfilled') {
        return result.value;
      } else {
        return {
          taskId: originalTask?.id || -1,
          success: false,
          error: result.reason?.message || 'Task failed'
        };
      }
    });

    // 更新批量任务进度
    if (this.batchTaskInfo) {
      this.batchTaskInfo.completedTasks = processedResults.filter(r => r.success).length;
    }

    // 清理批量任务的中止控制器
    this.batchAbortControllers = [];

    // 发送批量任务完成消息
    // 将处理后的结果发送回主线程
    self.postMessage({
      type: CommandResponse.Response_BatchTaskComplete,
      batchId,
      results: processedResults
    });

    this.isProcessing = false;
  }

  /**
   * 处理单个下载任务
   */
  // private async processTask(): Promise<void> {
  //   if (!this.currentTask) return;

  //   const { taskId, url, start, end, authToken, chunkIndex } = this.currentTask;
  //   let progressInterval: NodeJS.Timeout | null = null;

  //   try {
  //     // 持续检查暂停状态
  //     while (this.isPaused) {
  //       await new Promise<void>(resolve => {
  //         this.pauseResolver = resolve;
  //       });
  //       this.pauseResolver = null;
  //     }

  //     // 创建新的中止控制器
  //     this.abortController = new AbortController();

  //     // 准备请求选项
  //     const options: RequestOptions = {
  //       url: url,
  //       method: 'GET',
  //       timeout: Number.MAX_SAFE_INTEGER,
  //       returnResponse: true,
  //       signal: this.abortController.signal
  //     };
  //     options.headers = options.headers || {};
  //     options.headers['Range'] = `bytes=${start}-${end}`;

  //     if (authToken) {
  //       options.headers['Authorization'] = authToken;
  //     }

  //     // 移除定时器，改为在数据块读取时实时更新进度

  //     // 下载当前块
  //     const response = await request(options);

  //     // 检查是否已中止
  //     if (this.abortController.signal.aborted) {
  //       self.postMessage({
  //         type: CommandResponse.Response_TaskCanceled,
  //         taskId
  //       });
  //       return;
  //     }

  //     // 处理响应错误
  //     if (!response.ok) {
  //       if (response.status === 206) {
  //         // 206是部分内容响应，这是正常的分块下载状态
  //       } else {
  //         throw new Error(`HTTP error! status: ${response.status}`);
  //       }
  //     }

  //     // 确保响应有body
  //     if (!response.body) {
  //       throw new Error('Response body is null');
  //     }

  //     // 获取Reader
  //     const reader = response.body.getReader();
  //     const contentLength = Number(response.headers.get('Content-Length') || this.currentTask?.totalBytes || 0);

  //     // 实时处理下载流
  //     let receivedLength = 0;
  //     const chunks: Uint8Array[] = [];

  //     while (true) {
  //       const { done, value } = await reader.read();

  //       if (done) {
  //         break;
  //       }

  //       chunks.push(value);
  //       receivedLength += value.length;

  //       // 更新当前任务的下载进度
  //       if (this.currentTask) {
  //         this.currentTask.downloadedBytes = receivedLength;

  //         // 计算进度百分比
  //         const progress = this.currentTask.totalBytes > 0
  //           ? Math.min(100, Math.floor((receivedLength / this.currentTask.totalBytes) * 100))
  //           : 0;

  //         // 实时发送进度更新
  //         self.postMessage({
  //           type: CommandResponse.Response_Progress,
  //           taskId,
  //           progress
  //         });
  //       }

  //       // 检查是否已中止
  //       if (this.abortController?.signal.aborted) {
  //         self.postMessage({
  //           type: CommandResponse.Response_TaskCanceled,
  //           taskId
  //         });
  //         return;
  //       }
  //     }

  //     // 合并块数据
  //     const blob = new Blob(chunks);

  //     // 发送成功消息到主线程
  //     self.postMessage({
  //       type: CommandResponse.Response_TaskComplete,
  //       taskId,
  //       data: {
  //         chunkIndex,
  //         blob: blob
  //       }
  //     });

  //   } catch (error: unknown) {
  //     if (this.abortController?.signal.aborted) {
  //       self.postMessage({
  //         type: CommandResponse.Response_TaskCanceled,
  //         taskId,
  //         chunkIndex
  //       });
  //     } else if (this.retryCount < DownloadWorker.MAX_RETRIES) {
  //       // 重试下载
  //       this.retryCount++;
  //       self.postMessage({
  //         type: CommandResponse.Response_TaskRetry,
  //         taskId,
  //         retryCount: this.retryCount
  //       });
  //       // 指数退避
  //       await new Promise(resolve => setTimeout(resolve, 1000 * this.retryCount));
  //       // 重新调用处理函数
  //       return this.processTask();
  //     } else {
  //       console.log('下载失败', error);
  //       const errorMessage = error instanceof Error ? error.message : String(error);
  //       self.postMessage({
  //         type: CommandResponse.Response_TaskError,
  //         taskId,
  //         error: errorMessage
  //       });
  //     }
  //   } finally {
  //     // 清除进度更新定时器
  //     if (progressInterval) {
  //       clearInterval(progressInterval);
  //     }

  //     // 确保只有在重试情况下才保持处理状态
  //     if (this.retryCount < DownloadWorker.MAX_RETRIES && !this.abortController?.signal.aborted) {
  //       this.isProcessing = false;
  //       this.currentTask = null;
  //       this.abortController = null;
  //     }
  //   }
  // }
}

// ============== 初始化 ==============

// 创建DownloadWorker实例
// 在Worker线程中实例化下载处理器
const downloadWorker = new DownloadWorker();

// 监听主线程消息
// 注册消息事件监听器，将消息转发给DownloadWorker实例处理
self.addEventListener('message', (e) => {
  downloadWorker.handleMessage(e);
});

// 导出类型定义，方便主线程使用
// 注意：Worker 中不能直接导出，但我们可以在主线程中定义相同的类型
// 注意：Worker 中不能直接导出，但我们可以在主线程中定义相同的类型